<?php

namespace yuankezhan\htmlHelper\html;

use yuankezhan\htmlHelper\options\Options;
use yuankezhan\htmlHelper\Utils;

abstract class BaseHtml
{
    public function __construct($options = [])
    {
        $this->options = $this->optionClass()::set($options);
        $this->rootPath = Utils::rootPath();
        $this->loadResources();
    }

    /**
     * 标签名
     * @return mixed
     */
    abstract public function tagName();

    private function _baseResources()
    {
        return ['publicResources'];
    }

    protected function resources()
    {
        return [];
    }

    /**
     * 属性类文件
     * @return string
     */
    protected function optionClass()
    {
        return "{$this->rootNameSpace()}\options\Options";
    }

    /**
     * 没有闭合标签元素
     * @var string[]
     */
    protected $voidElements = [
        'area',
        'br',
        'hr',
        'img',
        'input',
        'meta',
    ];

    /**
     * @var Options $options
     */
    protected $options = null;

    /**
     * 根命名空间
     * @var string $rootNameSpace
     */
    protected function rootNameSpace()
    {
        return Utils::rootNameSpace();
    }

    /**
     * 根目录
     * @var string $rootPath
     */
    protected $rootPath;

    /**
     * 创建标签
     * @return mixed|string
     */
    public function create()
    {
        $name = $this->tagName();
        if (empty($className))
        {
            $className = "helper-create-{$name}";
        }
        $this->options->class = !empty($this->options->class) ? "{$this->options->class} $className" : $className;
        $content = $this->options->content;
        if ($name === null || $name === false) {
            return $content;
        }
        $html = "<$name {$this->setOptions()}>";
        return in_array(strtolower($name), $this->voidElements) ? $html : "$html$content</$name>";
    }

    /**
     * 设置标签属性
     * @return string
     */
    protected function setOptions()
    {
        $str = "";
        if ($this->options == null || empty($this->options->toArray()))
        {
            return $str;
        }
        foreach ($this->options->toArray() as $name => $value)
        {
            if (is_string($value))
            {
                $str .= " $name=\"" . $value . '"';
            }
        }
        return $str;
    }

    /**
     * 渲染页面
     * @param $file
     * @param $params
     * @return false|string
     */
    private function renderPhpFile($file, $params = [])
    {
        $obInitialLevel = ob_get_level();
        ob_start();
        ob_implicit_flush(false);
        extract($params, EXTR_OVERWRITE);
        try {
            require $file;
            return ob_get_clean();
        } catch (\Exception $e) {
            while (ob_get_level() > $obInitialLevel) {
                if (!@ob_end_clean()) {
                    ob_clean();
                }
            }
            throw $e;
        } catch (\Throwable $e) {
            while (ob_get_level() > $obInitialLevel) {
                if (!@ob_end_clean()) {
                    ob_clean();
                }
            }
            throw $e;
        }
    }

    /**
     * 加载资源文件件
     * @return void
     */
    private function loadResources()
    {
        $resources = array_merge($this->_baseResources(), $this->resources());
        foreach ($resources as $r)
        {
            $path = "{$this->rootPath}/resources/{$r}.php";
            if (file_exists($path))
            {
                require_once $path;
            }
        }
    }

    /**
     * 渲染页面
     * @param string $view 视图名称 路径 view
     * @param array $params 参数数组，键值对
     * @param array $resources 资源名称 路径 resources
     * @return string
     */
    public function render($view, $params = [])
    {
        try {
            $viewFile = "{$this->rootPath}/views/{$this->platform()}/{$view}.php";
            return $this->renderPhpFile($viewFile, $params);
        }
        catch (\Exception $e)
        {
            return $e->getMessage();
        }
    }

    /**
     * 根据手机还是pc返回  pc&mobile
     * @return string
     */
    public function platform()
    {
        if (Utils::isMobile())
        {
            return 'mobile';
        }
        return "pc";
    }
}